package com.xiaobias.distributed.pan.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.StreamProgress;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.xiaobias.distributed.pan.dto.BaiduPanFileList;
import com.xiaobias.distributed.pan.dto.ListsuccessRes;
import com.xiaobias.distributed.pan.utils.HttpTool;
import com.xiaobias.distributed.pan.web.messages.MyWebSocketHandler;
import com.xiaobias.distributed.pan.service.BaiduPanFileService;
import com.xiaobias.distributed.pan.service.BaiduPanTokenService;
import com.xiaobias.distributed.pan.utils.DataSizeUtil;
import com.xiaobias.distributed.pan.utils.FileUtils;

import java.io.*;
import java.util.*;
import javax.annotation.Resource;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Slf4j
@Service
public class BaiduPanFileServiceImpl
        implements BaiduPanFileService {

    @Resource
    private MyWebSocketHandler myWebSocketHandler;

    @Resource
    private BaiduPanFileService baiduPanFileService;
    @Resource
    private BaiduPanTokenService tokenService;

    private final RestTemplate restTemplate = new RestTemplate();

    public BaiduPanFileList getFileList(String dir, String folder) {
        String url = "https://pan.baidu.com/rest/2.0/xpan/file?method=list&access_token=" + this.tokenService.getToken();
        if (StringUtils.isNotEmpty(dir)) {
            String encodeBlank = URLUtil.encodeBlank(dir);
            url = url + "&dir=" + encodeBlank;
        }
        if (StringUtils.isNotEmpty(folder)) {
            url = url + "&folder=" + folder;
        }
        return this.restTemplate.getForObject(url, BaiduPanFileList.class, new Object[0]);
    }

    public String uploadFile(String panDir, String localFiles) {
        FileUtils.setAccessToken(this.tokenService.getToken());
        String filename;
        if (FileUtil.isFile(localFiles)) {
            filename = FileUtil.getName(localFiles);
        } else {
            return FileUtils.uploadDir(panDir, localFiles);
        }
        return FileUtils.upload(panDir, FileUtil.getParent(localFiles, 1), filename);
    }


    public Set<String> loopFiles(String dir) {
        Set<String> set = new HashSet<>();
        return getPathNames(dir, set);
    }

    @Override
    public String downloadFile(String dir, String tempPath) {
        if (StringUtils.isEmpty(dir)) {
            return "dir is empty";
        }

        // 启动定时器
        myWebSocketHandler.scheduleAtFixedRate();
        String token = this.tokenService.getToken();
        FileUtils.setAccessToken(token);
        StringBuilder sb = new StringBuilder();
        HashMap<String, List<String>> headers = new HashMap<>();
        headers.put("User-Agent", Collections.singletonList("pan.baidu.com"));

        // 创建队列存储待处理的下载任务（目录或文件）
        Queue<DownloadTask> taskQueue = new LinkedList<>();

        // 确定云端根目录的最后一级名称
        String lastPathSegment = getLastPathSegment(dir);
        String localRootPath = tempPath + File.separator + lastPathSegment;

        // 创建下载根目录任务
        taskQueue.add(new DownloadTask(dir, localRootPath));

        // 处理所有下载任务（包括递归的目录）
        while (!taskQueue.isEmpty()) {
            DownloadTask task = taskQueue.poll();
            String currentDir = task.getCloudPath();
            String localPath = task.getLocalPath();

            // 确保本地目录存在
            FileUtil.mkdir(localPath);

            // 获取当前目录的文件列表
            BaiduPanFileList currentFileList = this.baiduPanFileService.getFileList(currentDir, "");
            if (currentFileList == null || currentFileList.getList() == null) continue;

            for (ListsuccessRes res : currentFileList.getList()) {
                String fileName = res.getServerFilename();
                String cloudPath = currentDir + "/" + fileName;
                String localFilePath = localPath + File.separator + fileName;

                // 如果是目录，添加到队列进行递归处理
                if ("1".equals(res.getIsdir())) {
                    // 创建本地目录
                    FileUtil.mkdir(localFilePath);

                    // 添加到任务队列（递归处理）
                    taskQueue.add(new DownloadTask(cloudPath, localFilePath));
                    continue;
                }

                // 处理文件下载
                String downUrl = FileUtils.getDownUrl(fileName, currentDir);
                if (downUrl == null) {
                    continue;
                }
                downUrl = downUrl + "&access_token=" + token;
                sb.append(downUrl).append("\n");

                final String finalFileName = fileName;
                HttpTool.downloadFile(downUrl, new File(localFilePath), headers, new StreamProgress() {
                    @Override
                    public void start() {
                        String msg = "开始下载: " + finalFileName;
                        System.out.println(msg);
                        myWebSocketHandler.sendMessageToClient(msg);
                    }

                    @Override
                    public void progress(long totalPrototype, long sizePrototype) {
                        String total = DataSizeUtil.format(totalPrototype);
                        String size = DataSizeUtil.format(sizePrototype);
                        String msg = "{\"total\": \"" + total + "\", \"size\": \"" + size + "\", \"name\": \"" + finalFileName + "\", " +
                                "\"totalPrototype\": \"" + totalPrototype + "\", \"sizePrototype\": \"" + sizePrototype + "\"}";

                        log.debug(msg);
                        if (MyWebSocketHandler.sendStats.getAndSet(false) || sizePrototype == totalPrototype) {
                            myWebSocketHandler.sendMessageToClient(msg);
                        }
                    }

                    @Override
                    public void finish() {
                        String msg = "下载完成: " + finalFileName;
                        System.out.println(msg);
                        myWebSocketHandler.sendMessageToClient(msg);
                    }
                });
            }
        }

        // 关闭定时器
        myWebSocketHandler.cancelSchedule();

        return sb.toString();
    }

    // 提取路径的最后一段
    private String getLastPathSegment(String path) {
        // 标准化路径，去除开头和结尾的斜杠
        path = path.replaceAll("^/+|/+$", "");
        if (path.isEmpty()) return "root";

        // 分割路径并获取最后一部分
        String[] parts = path.split("/+");
        return parts[parts.length - 1];
    }

    // 辅助类：表示一个下载任务（目录或文件）
    @Getter
    private static class DownloadTask {
        private final String cloudPath; // 云端路径
        private final String localPath; // 本地保存路径

        public DownloadTask(String cloudPath, String localPath) {
            this.cloudPath = cloudPath;
            this.localPath = localPath;
        }

    }

    @Override
    public JSONObject getFileListByAccount(String account, String dir) {
        String url = "https://pan.baidu.com/rest/2.0/xpan/file?method=list&access_token=" + account + "&folder=1";
        if (StringUtils.isNotEmpty(dir)) {
            String encodeBlank = URLUtil.encodeBlank(dir);
            url = url + "&dir=" + encodeBlank;
        }
        return this.restTemplate.getForObject(url, JSONObject.class, new Object[0]);
    }

    private Set<String> getPathNames(String dir, Set<String> set) {
        File f = new File(dir);
        if (!f.exists()) {
            System.out.println(dir + " not exists");
            return set;
        }
        File[] fa = f.listFiles();
        if (fa != null) {
            for (File fs : fa) {
                String path = fs.getPath();
                if (fs.isDirectory()) {
                    getPathNames(path, set);
                }
                System.out.println(path);
                set.add(path);
            }
        }
        return set;
    }
}